package com.baidu.sggc.controller;

import com.baidu.sggc.core.common.R;
import com.baidu.sggc.data.req.AuditLogReq;
import com.baidu.sggc.entity.AuditQueryLogDTO;
import com.baidu.sggc.entity.UserContext;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.fasterxml.jackson.databind.ObjectMapper;

import javax.servlet.http.HttpServletRequest;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/api/audit")
@Slf4j
public class AuditLogController {

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
    private static final String AUDIT_LOG_FILE = "/var/log/sggc/query_audit.log";

    @PostMapping("/queryLog")
    public R<Void> saveAuditLog(@RequestBody AuditLogReq auditLogReq, HttpServletRequest request) throws JsonProcessingException {
        // 打印日志
        log.info("【审计日志上报】操作类型:{}，参数:{}", auditLogReq.getOperation(), auditLogReq);
        if (auditLogReq.getExtendData() != null) {
            log.info("【审计日志-ExtendData】内容: {}", auditLogReq.getExtendData());
        }

        // 构造对象
        AuditQueryLogDTO auditLogDTO = new AuditQueryLogDTO();
        auditLogDTO.setUserId(UserContext.getUserId());
        auditLogDTO.setUserName(UserContext.getUserName());
        auditLogDTO.setOperation(auditLogReq.getOperation());
        auditLogDTO.setMenuPath(auditLogReq.getMenuPath());
        auditLogDTO.setAccessAddress(getClientIp(request));
        auditLogDTO.setExtendData(OBJECT_MAPPER.writeValueAsString(convertTimestamps(auditLogReq.getExtendData())));
        auditLogDTO.setOperateState("success");
        String operateTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        auditLogDTO.setOperateTime(operateTime);

        // 写入日志文件，每行为一个JSON对象
        try {
            String jsonLog = OBJECT_MAPPER.writeValueAsString(auditLogDTO);
            Files.write(
                    Paths.get(AUDIT_LOG_FILE),
                    (jsonLog + System.lineSeparator()).getBytes(StandardCharsets.UTF_8),
                    StandardOpenOption.CREATE, StandardOpenOption.APPEND
            );
        } catch (Exception e) {
            log.error("写入审计日志文件失败", e);
        }

        return R.ok();
    }


    public static String getClientIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
            // 多个IP, 取第一个
            if (ip.contains(",")) {
                ip = ip.split(",")[0].trim();
            }
            return ip;
        }
        ip = request.getHeader("Proxy-Client-IP");
        if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
            return ip;
        }
        ip = request.getHeader("WL-Proxy-Client-IP");
        if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
            return ip;
        }
        ip = request.getRemoteAddr();
        return ip;
    }


    @SuppressWarnings("unchecked")
    private Object convertTimestamps(Object data) {
        if (data instanceof Map) {
            Map<String, Object> map = (Map<String, Object>) data;
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                Object value = entry.getValue();
                if (value instanceof Number) {
                    long ts = ((Number) value).longValue();
                    // 判断是否像是时间戳（秒级/毫秒级）
                    if (String.valueOf(ts).length() == 10 || String.valueOf(ts).length() == 13) {
                        entry.setValue(formatTimestamp(ts));
                    }
                } else {
                    entry.setValue(convertTimestamps(value)); // 递归
                }
            }
            return map;
        } else if (data instanceof List) {
            List<Object> list = (List<Object>) data;
            for (int i = 0; i < list.size(); i++) {
                list.set(i, convertTimestamps(list.get(i))); // 递归
            }
            return list;
        }
        return data;
    }

    private String formatTimestamp(long timestamp) {
        // 如果是秒级时间戳，转成毫秒级
        if (String.valueOf(timestamp).length() == 10) {
            timestamp = timestamp * 1000;
        }
        return LocalDateTime.ofInstant(
                Instant.ofEpochMilli(timestamp),
                ZoneId.of("Asia/Shanghai")
        ).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }

}
